package model.readers;


import static com.nightpiter.controller.log.Logger.log;
import static com.nightpiter.controller.log.Logger.logException;
import gui.view.android.AndroidDrawersRegistry;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import com.nightpiter.controller.log.Logger;
import com.nightpiter.view.drawer.MetroDrawer;

public class ReadersRegistry {
	private static List<FileFormat> formats = new LinkedList<FileFormat>(); 
	
	public static class FileFormat {
		public String shortFileFormatDescription;
		public String formatFileNameExtension;
		public MetroReader reader;
		FileFormat(String shortFormatDescription, String fileExtension, MetroReader reader){
			this.shortFileFormatDescription = shortFormatDescription;
			this.formatFileNameExtension = fileExtension;
			this.reader = reader;
		}
	}
	public static void addFormat(String shortFormatDescription, String fileExtension, MetroReader reader) {
		formats.add(new FileFormat(shortFormatDescription, fileExtension, reader));
		MetroModelReaderFactory.associate(shortFormatDescription, fileExtension, reader);
	}
	
	public static List<FileFormat> getFormats() {
		return formats;
	}
	
	public static void getReaderFromJar(String path) {
		JarFile file;
		try {
			file = new JarFile(new File(path));
			LinkedList<EventsHandler.DrawerStruct> readers = new LinkedList<EventsHandler.DrawerStruct>(); 
			SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
			XMLReader xr = parser.getXMLReader();
			EventsHandler handler = new EventsHandler(readers);

			xr.setContentHandler(handler);
			xr.setErrorHandler(handler);

			InputSource inputSource = new InputSource(file.getInputStream(file.getJarEntry("manifest.xml")));

			xr.parse(inputSource);

			for(EventsHandler.DrawerStruct reader:readers) {
				String className = reader.prefix +"."+ reader.mainClass;

				try {
					URLClassLoader loader = new URLClassLoader(new URL[]{new URL("file:///"+path)});
					//System.out.print(loader.loadClass(className).getPackage());
					ReadersRegistry.addFormat(reader.description, reader.extensions.get(0), (MetroReader) loader.loadClass(className).newInstance());
				} catch (MalformedURLException e) {
					e.printStackTrace();
				}
			}
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FactoryConfigurationError fce) {
			logException(fce);
			log("Parsing failed");
		} catch (ParserConfigurationException pce) {
			logException(pce);
			log("Parsing failed");
		} catch (SAXParseException spe) {
			logException(spe);
			log("Parsing failed");
		} catch (SAXException saxe) {
			logException(saxe);
			log("Parsing failed");
		} catch (IOException e) {		
			e.printStackTrace();
		}
	}




}



//TODO move somewere

class EventsHandler extends DefaultHandler {
	
	public static class DrawerStruct {
		public String prefix;
		public String mainClass;
		public List<String> extensions = new ArrayList<String>();
		public String description;
	}	

	public static final String ROOT = "manifest";

	public static final String CONTENT = "content";

	public static final String NAME = "name";

	public static final String DESCRIPTION = "description";

	public static final String FORMAT = "format";

	public static final String EXTENSION = "extension";

	public static final String VERSION = "version";

	public static final String AUTHORS = "authors";

	public static final String AUTHOR = "author";

	public static final String NOTE = "note";

	public static final String MODULES = "modules";

	public static final String MODULE = "module";

	public static final String PACK = "pack";

	public static final String PREFIX = "prefix";

	public static final String CLASSES = "classes";

	public static final String CLASS = "class";

	public static final String ID_ATTR = "id";

	public static final String MAIN_ATTR = "main";

	LinkedList<DrawerStruct> dStruct;
	public static final String LAST_MODIFIED_ATTR = "last-modified";
	private String version = null;

	private Stack<String> stack;
	
	private boolean nextClassIsMain = false;
	
	private int mainID = -1;
	

	public EventsHandler(LinkedList<DrawerStruct> drStruct) {
		super();
		this.dStruct = drStruct;
		this.stack = new Stack<String>();
	}

	public void startDocument() {
	}

	public void endDocument() {
	}

	public void startElement(String uri, String qName, String name,
			Attributes attrs) {

		stack.push(name);
		String path = getPath();			
		if (getPath().equals(ROOT + MODULES + MODULE + CLASSES + CLASS)) {
			int id = Integer.parseInt(attrs.getValue(ID_ATTR));
			if(id==mainID) this.nextClassIsMain = true;

		} else if (path.equals(ROOT + MODULES + MODULE + CLASSES)) {
			int main = Integer.parseInt(attrs.getValue(MAIN_ATTR));
			mainID = main;

		}
		

		
	}
	
	public void endElement(String uri, String qname, String name) {

	

		

		stack.pop();
	}

	@Override
	public void characters(char ch[], int start, int length) {
		String path = getPath();
		if (path.equals(ROOT + MODULES + MODULE + CLASSES + CLASS)) {
			if(this.nextClassIsMain) dStruct.getLast().mainClass = new String(ch, start, length);
			this.nextClassIsMain = false;
		} else if (path.equals(ROOT + MODULES + MODULE + PREFIX)) {
			dStruct.add(new DrawerStruct());
			dStruct.getLast().prefix = new String(ch, start, length);
		 } else if (path.equals(ROOT + MODULES + MODULE + FORMAT + EXTENSION)) {
			dStruct.getLast().extensions.add(new String(ch, start, length));
		 } else if (path.equals(ROOT + MODULES + MODULE + FORMAT + DESCRIPTION)) {
			dStruct.getLast().description = new String(ch, start, length);
		 }
		

		
	}

	private String getPath() {
		String path = "";
		for (int i = 0; i < stack.size(); i++) {
			path += stack.get(i);
		}
		return path;
	}
}

